/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bgu.ppm.dat.view;

import bgu.ppm.dat.model.AggregatedField;
import bgu.ppm.dat.model.AggregationFunction;
import bgu.ppm.dat.model.Field;
import bgu.ppm.dat.model.FilterField;
import bgu.ppm.dat.model.Pivot;
import bgu.sonar.util.collections.obs.ObservableList;
import bgu.sonar.util.ui.models.AbstractTabularModel;
import bgu.sonar.util.ui.tables.ScrollableStripeTable;
import java.awt.Component;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.Collection;
import javax.swing.AbstractAction;
import javax.swing.DefaultCellEditor;
import javax.swing.DropMode;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JTable;
import javax.swing.TransferHandler;
import static javax.swing.TransferHandler.COPY;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import org.openide.util.datatransfer.ExTransferable;

/**
 *
 * @author User
 */
public class PivotView extends javax.swing.JPanel {

    public static final FieldFlavor FIELD_FLAVOR = new FieldFlavor();
    private Pivot model;
    private AbstractTabularModel<Field> fieldTableModel;

    /**
     * Creates new form PivotView
     */
    public PivotView() {
        initComponents();

        fieldTable.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                JComponent c = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); //To change body of generated methods, choose Tools | Templates.
                c.setBorder(null);
                return c;
            }
        });

        final TableCellRenderer inner = fieldTable.getDefaultRenderer(Boolean.class);
        fieldTable.setDefaultRenderer(Boolean.class, new TableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                JComponent c = (JComponent) inner.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                c.setBorder(null);
                return c;
            }
        });

        fieldTable.setColumnWidth("Selected?", 30);

//        filterfTree.setCellRenderer(new CheckBoxNodeRenderer());
//        filterfTree.setCellEditor(new CheckBoxNodeEditor(filterfTree));
        fieldTable.setTransferHandler(new TransferHandler() {
            @Override
            protected Transferable createTransferable(JComponent c) {
                Transferable t = super.createTransferable(c);
                return new ExTransferable.Single(FIELD_FLAVOR) {
                    @Override
                    protected Object getData() throws IOException, UnsupportedFlavorException {
                        return fieldTable.getSelectedRow();
                    }
                };
            }

            @Override
            public int getSourceActions(JComponent c) {
                return COPY;
            }
        });

    }

    private void setupFieldSelectionModels() {
        setupFieldSelectionModel(this.columnsTable, model.getSelectedSeriesFields(), TransferAction.Series);
        setupFieldSelectionModel(this.rowsTable, model.getSelectedAxisFields(), TransferAction.Axis);
        setupFilterSelectionModel();
        setupValuesModel();
    }

    public void setModel(Pivot pivot) {
        this.model = pivot;

        fieldTableModel = new AbstractTabularModel<Field>("Selected?", "Name") {
            @Override
            public Object extractValue(Field element, String value) {
                switch (value) {
                    case "Selected?":
                        return model.isInUse(element);
                    default:
                        return element.getFieldName();
                }
            }

            @Override
            public void importValue(Field element, String column, Object value) {
                switch (column) {
                    case "Selected?": {
                        Boolean v = (Boolean) value;

                        if (!v) {
                            model.removeUseOf(element);
                        }

                        break;
                    }
                    default: {
                        try {
                            element.setFieldName("" + value);
                        } catch (Exception e) {
                            JOptionPane.showMessageDialog(null, e.getMessage(), "Name error", JOptionPane.ERROR_MESSAGE);
                        }
                    }
                }

                setupFieldSelectionModels();
            }
        };

        fieldTableModel.setColumnEditable(0, Boolean.class);
        fieldTableModel.setColumnEditable(1, String.class);
        fieldTableModel.getElements().addAll(pivot.getAvailableRawFields());

        fieldTable.setModel(fieldTableModel);
        setupFieldSelectionModels();

    }

    private void setupValuesModel() {
        this.valuesTable.setDefaultEditor(AggregationFunction.class, new DefaultCellEditor(new JComboBox(model.getAggregationFunctions().toArray())));

        AbstractTabularModel<AggregatedField> tModel = new AbstractTabularModel<AggregatedField>("Name", "AggregationFunction") {
            @Override
            public Object extractValue(AggregatedField element, String value) {
                switch (value) {
                    case "Name":
                        return element.getFieldName();
                    default:
                        return element.getAggregationFunction();
                }
            }

            @Override
            public void importValue(AggregatedField element, String column, Object value) {
                switch (column) {
                    case "Name":
                        element.setFieldName("" + value);
                        break;
                    default:
                        element.setAggregationFunction((AggregationFunction) value);
                        break;
                }

                valuesTable.notifyChange();
            }
        };

        tModel.setColumnEditable(1, AggregationFunction.class);
        tModel.setColumnEditable(0, String.class);
        tModel.getElements().addAll(model.getSelectedValuesFields());

        valuesTable.setModel(tModel);

        setupTransferable(valuesTable, TransferAction.Values);

        setupDeleteAction(valuesTable);
    }

    private void setupFilterSelectionModel() {
        final DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(new SelecteableItem<>("root", false));
        TreeModel tModel = new DefaultTreeModel(rootNode);

        for (Object f : model.getSelectedFilterFields()) {
            FilterField ff = (FilterField) f;
            DefaultMutableTreeNode filterNode = new DefaultMutableTreeNode(new FilterFieldSelectableItem(ff));
            for (Object v : ff.getAllValues()) {
                filterNode.add(new DefaultMutableTreeNode(new FilterFieldValueSelectableItem(ff, v), false));
            }
            rootNode.add(filterNode);
        }

        filterTree.setModel(tModel);
        filterTree.setDragEnabled(true);
        filterTree.setDropMode(DropMode.ON);

        filterTree.setTransferHandler(new TransferHandler() {
            @Override
            public boolean canImport(TransferHandler.TransferSupport support) {
                Field element = fieldTableModel.getElementAt(fieldTable.getSelectedRow());

                for (Object e : model.getSelectedFilterFields()) {
                    if (element.getFieldId() == ((FilterField) e).getFieldId()) {
                        return false;
                    }
                }

                return support.getDataFlavors()[0] == FIELD_FLAVOR;
            }

            @Override
            public boolean importData(TransferHandler.TransferSupport support) {
                Field element = fieldTableModel.getElementAt(fieldTable.getSelectedRow());
                FilterField ff = model.selectFilterField(element);
                DefaultMutableTreeNode filterNode = new DefaultMutableTreeNode(new FilterFieldSelectableItem(ff));
                for (Object v : ff.getAllValues()) {
                    filterNode.add(new DefaultMutableTreeNode(new FilterFieldValueSelectableItem(ff, v), false));
                }
                rootNode.add(filterNode);
                setupFieldSelectionModels();
                return true;
            }
        });
    }

    private void setupFieldSelectionModel(final ScrollableStripeTable table, final Collection<Field> data, TransferAction action) {
        AbstractTabularModel<Field> tModel = new AbstractTabularModel<Field>("Name") {
            @Override
            public Object extractValue(Field element, String value) {
                return element.getFieldName();
            }

            @Override
            public void importValue(Field element, String column, Object value) {
                try {
                    element.setFieldName("" + value);
                } catch (Exception e) {
                    JOptionPane.showMessageDialog(null, e.getMessage(), "Name error", JOptionPane.ERROR_MESSAGE);
                }
                fieldTable.notifyChange();
            }
        };

        tModel.setColumnEditable(0, String.class);
        tModel.getElements().addAll(data);

        table.setModel(tModel);
        setupTransferable(table, action);

        setupDeleteAction(table);
    }

    private void setupTransferable(final ScrollableStripeTable table, final TransferAction action) {
        table.setTransferHandler(new TransferHandler() {
            @Override
            public boolean canImport(TransferHandler.TransferSupport support) {
                Field element = fieldTableModel.getElementAt(fieldTable.getSelectedRow());

                switch (action) {
                    case Axis:
                        for (Object e : model.getSelectedAxisFields()) {
                            if (element.getFieldId() == ((Field) e).getFieldId()) {
                                return false;
                            }
                        }
                        break;
                    case Filter:
                        break;
                    case Series:
                        for (Object e : model.getSelectedSeriesFields()) {
                            if (element.getFieldId() == ((Field) e).getFieldId()) {
                                return false;
                            }
                        }
                        break;
                    case Values:
                        break;
                }
                return support.getDataFlavors()[0] == FIELD_FLAVOR;
            }

            @Override
            public boolean importData(TransferHandler.TransferSupport support) {
                Field element = fieldTableModel.getElementAt(fieldTable.getSelectedRow());
                action.handleTransfer(model, (AbstractTabularModel) table.getModel(), element);
                setupFieldSelectionModels();
                return true;
            }
        });
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        jSplitPane1 = new javax.swing.JSplitPane();
        jPanel2 = new javax.swing.JPanel();
        jPanel3 = new javax.swing.JPanel();
        columnsTable = new bgu.sonar.util.ui.tables.ScrollableStripeTable();
        jLabel4 = new javax.swing.JLabel();
        jPanel4 = new javax.swing.JPanel();
        jLabel2 = new javax.swing.JLabel();
        filterTree = new bgu.ppm.dat.view.CheckBoxTextEditingTreeView();
        jPanel5 = new javax.swing.JPanel();
        valuesTable = new bgu.sonar.util.ui.tables.ScrollableStripeTable();
        jLabel5 = new javax.swing.JLabel();
        jPanel6 = new javax.swing.JPanel();
        rowsTable = new bgu.sonar.util.ui.tables.ScrollableStripeTable();
        jLabel3 = new javax.swing.JLabel();
        jPanel1 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        fieldTable = new bgu.sonar.util.ui.tables.ScrollableStripeTable();

        setLayout(new java.awt.BorderLayout());

        jSplitPane1.setDividerLocation(200);
        jSplitPane1.setDividerSize(2);
        jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);

        jPanel2.setPreferredSize(new java.awt.Dimension(916, 300));
        jPanel2.setLayout(new java.awt.GridBagLayout());

        jPanel3.setBackground(new java.awt.Color(255, 255, 255));
        jPanel3.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(238, 238, 238)));
        jPanel3.setLayout(new java.awt.GridBagLayout());

        columnsTable.setDragEnabled(true);
        columnsTable.setDropMode(javax.swing.DropMode.INSERT_ROWS);
        columnsTable.setEvenRowColor(new java.awt.Color(255, 255, 255));
        columnsTable.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {

            }
        ));
        columnsTable.setMultiSelectionEnabled(false);
        columnsTable.setOddRowColor(new java.awt.Color(255, 255, 255));
        columnsTable.setShowGridLines(false);
        columnsTable.setShowHeaders(false);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        jPanel3.add(columnsTable, gridBagConstraints);

        jLabel4.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
        org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(PivotView.class, "PivotView.jLabel4.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        jPanel3.add(jLabel4, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        jPanel2.add(jPanel3, gridBagConstraints);

        jPanel4.setBackground(new java.awt.Color(255, 255, 255));
        jPanel4.setLayout(new java.awt.GridBagLayout());

        jLabel2.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
        org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(PivotView.class, "PivotView.jLabel2.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        jPanel4.add(jLabel2, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        jPanel4.add(filterTree, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        jPanel2.add(jPanel4, gridBagConstraints);

        jPanel5.setBackground(new java.awt.Color(255, 255, 255));
        jPanel5.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(238, 238, 238)));
        jPanel5.setLayout(new java.awt.GridBagLayout());

        valuesTable.setDragEnabled(true);
        valuesTable.setDropMode(javax.swing.DropMode.INSERT_ROWS);
        valuesTable.setEvenRowColor(new java.awt.Color(255, 255, 255));
        valuesTable.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {

            }
        ));
        valuesTable.setMultiSelectionEnabled(false);
        valuesTable.setOddRowColor(new java.awt.Color(255, 255, 255));
        valuesTable.setShowGridLines(false);
        valuesTable.setShowHeaders(false);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        jPanel5.add(valuesTable, gridBagConstraints);

        jLabel5.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
        org.openide.awt.Mnemonics.setLocalizedText(jLabel5, org.openide.util.NbBundle.getMessage(PivotView.class, "PivotView.jLabel5.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        jPanel5.add(jLabel5, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        jPanel2.add(jPanel5, gridBagConstraints);

        jPanel6.setBackground(new java.awt.Color(255, 255, 255));
        jPanel6.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(238, 238, 238)));
        jPanel6.setLayout(new java.awt.GridBagLayout());

        rowsTable.setDragEnabled(true);
        rowsTable.setDropMode(javax.swing.DropMode.INSERT_ROWS);
        rowsTable.setEvenRowColor(new java.awt.Color(255, 255, 255));
        rowsTable.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {

            }
        ));
        rowsTable.setMultiSelectionEnabled(false);
        rowsTable.setOddRowColor(new java.awt.Color(255, 255, 255));
        rowsTable.setShowGridLines(false);
        rowsTable.setShowHeaders(false);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        jPanel6.add(rowsTable, gridBagConstraints);

        jLabel3.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
        org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(PivotView.class, "PivotView.jLabel3.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        jPanel6.add(jLabel3, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        jPanel2.add(jPanel6, gridBagConstraints);

        jSplitPane1.setRightComponent(jPanel2);

        jPanel1.setBackground(new java.awt.Color(255, 255, 255));
        jPanel1.setLayout(new java.awt.GridBagLayout());

        jLabel1.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
        org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(PivotView.class, "PivotView.jLabel1.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        jPanel1.add(jLabel1, gridBagConstraints);

        fieldTable.setDragEnabled(true);
        fieldTable.setDropMode(javax.swing.DropMode.INSERT_ROWS);
        fieldTable.setEnabled(false);
        fieldTable.setEvenRowColor(new java.awt.Color(255, 255, 255));
        fieldTable.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {

            }
        ));
        fieldTable.setMultiSelectionEnabled(false);
        fieldTable.setOddRowColor(new java.awt.Color(255, 255, 255));
        fieldTable.setShowGridLines(false);
        fieldTable.setShowHeaders(false);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        jPanel1.add(fieldTable, gridBagConstraints);

        jSplitPane1.setLeftComponent(jPanel1);

        add(jSplitPane1, java.awt.BorderLayout.CENTER);
    }// </editor-fold>//GEN-END:initComponents
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private bgu.sonar.util.ui.tables.ScrollableStripeTable columnsTable;
    private bgu.sonar.util.ui.tables.ScrollableStripeTable fieldTable;
    private bgu.ppm.dat.view.CheckBoxTextEditingTreeView filterTree;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JPanel jPanel5;
    private javax.swing.JPanel jPanel6;
    private javax.swing.JSplitPane jSplitPane1;
    private bgu.sonar.util.ui.tables.ScrollableStripeTable rowsTable;
    private bgu.sonar.util.ui.tables.ScrollableStripeTable valuesTable;
    // End of variables declaration//GEN-END:variables

    private void setupDeleteAction(final ScrollableStripeTable table) {
        final JPopupMenu pop = new JPopupMenu();
        pop.add(new AbstractAction("Delete") {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (table.getSelectedRow() >= 0) {
                    final ObservableList<Field> elements = ((AbstractTabularModel<Field>) table.getModel()).getElements();
                    Field element = elements.get(table.getSelectedRow());
                    elements.remove(element);
                    model.removeUseOf(element);
                    fieldTable.notifyChange();
                }
            }
        });

        table.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getButton() == MouseEvent.BUTTON3) {
                    pop.show(table, e.getX(), e.getY());
                }
            }
        });
    }

    public static class FieldFlavor extends DataFlavor {

        public FieldFlavor() {
            super(Field.class, "Field");
        }
    }

    private enum TransferAction {

        Series {
            @Override
            public void handleTransfer(Pivot model, AbstractTabularModel tabularModel, Field field) {
                tabularModel.getElements().add(model.selectSeriesField(field));
            }
        }, Values {
            @Override
            public void handleTransfer(Pivot model, AbstractTabularModel tabularModel, Field field) {
                tabularModel.getElements().add(model.selectValuesField(field));
            }
        }, Axis {
            @Override
            public void handleTransfer(Pivot model, AbstractTabularModel tabularModel, Field field) {
                tabularModel.getElements().add(model.selectAxisField(field));
            }
        }, Filter {
            @Override
            public void handleTransfer(Pivot model, AbstractTabularModel tabularModel, Field field) {
                tabularModel.getElements().add(model.selectFilterField(field));
            }
        };

        public abstract void handleTransfer(Pivot model, AbstractTabularModel tabularModel, Field field);
    }
}
